<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <div id="app">
    <span>姓名：{{ name }}</span>
    <input type="text" v-model="name"></input>
    <span>{{more.like}}</span>
    <input type="text" v-model="more.like"></input>
  </div>
  <script>

    class Dependance {
      constructor() {
        this.subscribers = []; // 订阅者数组
      }

      addSub (sub) { // 添加订阅者
        this.subscribers.push(sub);
      }

      notify () { // 通知订阅者更新
        this.subscribers.forEach(sub => sub.update());
      }
    }
    class Watcher {
      constructor(vm, key, cb) {
        this.vm = vm; // vue实例
        this.key = key; // 数据名
        this.callback = cb; // 回调函数 
        Dependance.tmp = this; // 缓存自己
        console.log(`用属性${key}创建了订阅者`)
        // 触发getter
        key.split('.').reduce(
          (total, current) => total[current], vm.$data
        )
        Dependance.tmp = null; // 释放自己
      }
      update () { // 更新
        const value = this.key.split('.').reduce(
          (total, current) => total[current], this.vm.$data
        );
        this.callback(value);
      }
    }

    // 替换html里面的{{}}的值
    function Compile (element, vm) {
      vm.$el = document.querySelector(element);
      const fragment = document.createDocumentFragment();
      let child;
      // 移动DOM元素到文档碎片
      while (child = vm.$el.firstChild) {
        fragment.append(child);
      }
      console.log('fragment',fragment)
      // 碎片编译
      function fragment_compile (node) {
        console.log('node',node.nodeType,node.name )
        const pattern = /\{\{\s*(\S+)\s*\}\}/;
        if (node.nodeType === 3) { // 文本节点
          const xxx = node.nodeValue;
          const result_regex = pattern.exec(node.nodeValue);
          if (result_regex) {
            // 层级属性访问（如data.user.name）
            const arr = result_regex[1].split('.');
            const value = arr.reduce(
              (total, current) => total[current], vm.$data
            );
            node.nodeValue = xxx.replace(pattern, value);
            new Watcher(vm, result_regex[1], (newValue) => {
              node.nodeValue = xxx.replace(pattern, newValue);
            })
          }
          return
        }
        // 检测 input 元素节点
        if (node.nodeType === 1) {
          const attr = Array.from(node.attributes);

          // 遍历属性查找 v-model 指令
          attr.forEach(i => {
            if (i.nodeName === 'v-model') {
              // 初始化数据绑定
              const value = i.nodeValue.split('.').reduce(
                (total, current) => total[current], vm.$data
              );
              node.value = value;

              // 注册数据监听器
              new Watcher(vm, i.nodeValue, newValue => {
                node.value = newValue;
              });

              // 实现视图到数据的更新
              node.addEventListener('input', e => {
                const arr1 = i.nodeValue.split('.');
                const arr2 = arr1.slice(0, -1);
                const final = arr2.reduce(
                  (total, current) => total[current], vm.$data
                );
                final[arr1.pop()] = e.target.value;
              });
            }
          });
        }
        node.childNodes.forEach(child => fragment_compile(child));
      }
      fragment_compile(fragment);
      vm.$el.appendChild(fragment);
    }

    function Observe (data_instance) {
      if (!data_instance || typeof data_instance !== 'object') return;
      const dependance = new Dependance();
      Object.keys(data_instance).forEach(key => {
        let value = data_instance[key];
        Observe(value);
        Object.defineProperty(data_instance, key, {
          enumerable: true,
          configurable: true,
          get () {
            console.log(`key:${key}---value:${value}`)
            Dependance.tmp && dependance.addSub(Dependance.tmp)
            if (Dependance.tmp) {
              console.log(Dependance.tmp)
            }
            return value;
          },
          set (newValue) {
            value = newValue;
            Observe(newValue)
            dependance.notify();

          }
        })

      })

    }
    class Vue {
      constructor(obj_instance) {
        this.$data = obj_instance.data;
        Observe(this.$data)
        Compile(obj_instance.el, this)
      }
    }

    const vm = new Vue({
      el: '#app',
      data: {
        name: 'zs',
        more: {
          like: 'eat'
        }
      }
    })
    console.log(vm)
  </script>
</body>

</html>